from typing import List


def _normalize_thread_name(thread_name: str) -> str:
    if not thread_name:
        return ""
    return thread_name[-15:]

def get_time_range(cursor):
    cursor.execute("SELECT start_ts, end_ts FROM trace_range")
    return cursor.fetchone()

def get_last_touch_event(cursor, start_ts, end_ts):
    if start_ts is None or end_ts is None:
        return get_time_range(cursor)
    cursor.execute("SELECT ts, ts+dur FROM callstack WHERE name in ('H:touchEventDispatch', 'H:PointerEventDispatch') and ts >= ? and ts <= ? order by ts desc limit 1", (start_ts, end_ts))
    return cursor.fetchone()

def get_function_cost(cursor, function_name, start_ts=None, end_ts=None, ancestor_name=None, thread_name=""):
    # 截取 thread_name 的最后 15 个字符
    thread_name = _normalize_thread_name(thread_name)
    query = """
    SELECT ts as start_ts, (ts + dur) as end_ts, dur as duration FROM callstack 
    JOIN thread ON callstack.callid = thread.itid
    WHERE callstack.name LIKE ?
    """
    params = [f"%{function_name}%"]
    if start_ts:
        query += " and ts >= ?"
        params.append(start_ts)
    if end_ts:
        query += " and ts + dur <= ?"
        params.append(end_ts)
    if thread_name:
        query += " and thread.name LIKE ?"
        params.append(f"%{thread_name}%")

    if ancestor_name:
        query += """
        AND callstack.parent_id IN (
            WITH RECURSIVE ancestor_ids(id) AS (
                SELECT id FROM callstack WHERE name LIKE ?
                UNION ALL
                SELECT parent_id FROM callstack WHERE parent_id IN (SELECT id FROM ancestor_ids)
                AND parent_id != 4294967295
            )
            SELECT id FROM ancestor_ids
        )
        """
        params.append(ancestor_name)

    query += " ORDER BY ts"

    cursor.execute(query, tuple(params))
    return cursor.fetchall()

def get_so_load_cost(cursor, start_ts=None, end_ts=None, thread_name=""):
    query = """
    SELECT ts as start_ts, (ts + dur) as end_ts, dur as duration, callstack.name as name FROM callstack 
    JOIN thread ON callstack.callid = thread.itid
    WHERE callstack.name LIKE '%.so%'
    """
    params = []
    if start_ts:
        query += " and ts >= ?"
        params.append(start_ts)
    if end_ts:
        query += " and ts + dur <= ?"
        params.append(end_ts)
    if thread_name:
        thread_name = _normalize_thread_name(thread_name)
        query += " and thread.name LIKE ?"
        params.append(f"%{thread_name}%")
    query += " ORDER BY ts"
    cursor.execute(query, tuple(params))
    return cursor.fetchall()

def get_first_event_after(cursor, name_patterns, start_ts=None, end_ts=None, thread_name=""):
    if isinstance(name_patterns, str):
        name_patterns = [name_patterns]
    if not name_patterns:
        raise ValueError("name_patterns is required")
    clauses = []
    params = []
    for pattern in name_patterns:
        clauses.append("callstack.name LIKE ?")
        params.append(pattern)
    query = """
    SELECT ts as start_ts, (ts + dur) as end_ts, dur as duration, callstack.name as name FROM callstack
    JOIN thread ON callstack.callid = thread.itid
    WHERE ({})
    """.format(" OR ".join(clauses))
    if start_ts is not None:
        query += " AND ts >= ?"
        params.append(start_ts)
    if end_ts is not None:
        query += " AND ts <= ?"
        params.append(end_ts)
    if thread_name:
        query += " AND thread.name LIKE ?"
        params.append(f"%{_normalize_thread_name(thread_name)}%")
    query += " ORDER BY ts LIMIT 1"
    cursor.execute(query, tuple(params))
    return cursor.fetchone()

def get_thread_time_bounds(cursor, thread_name: str):
    thread_name = _normalize_thread_name(thread_name)
    query = """
    SELECT MIN(callstack.ts), MAX(callstack.ts + callstack.dur)
    FROM callstack
    JOIN thread ON callstack.callid = thread.itid
    """
    params: List[object] = []
    if thread_name:
        query += " WHERE thread.name LIKE ?"
        params.append(f"%{thread_name}%")
    cursor.execute(query, tuple(params))
    result = cursor.fetchone()
    if not result:
        return None, None
    return result[0], result[1]
def detect_main_thread(cursor):
    """
    通过统计 callstack 的总耗时确定最活跃的线程，作为主线程候选。
    """
    cursor.execute(
        """
        SELECT thread.name, SUM(callstack.dur) as total_dur
        FROM callstack
        JOIN thread ON callstack.callid = thread.itid
        WHERE thread.name IS NOT NULL AND thread.name != ''
        GROUP BY thread.name
        ORDER BY total_dur DESC
        LIMIT 1
        """
    )
    row = cursor.fetchone()
    return row[0] if row else ""
